package org.opens.util;

import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/**
 * 说明：
 * <pre>
 *     1. 目前这种算法是有问题的-买100张不一样票号的彩票并不能使各自的中奖率上升10倍；
 * </pre>
 */
public class LotteryUtil {

    public static final Double FIRST_PRIZE_BONUS = 500_0000D;
    public static final Double SECOND_PRIZE_BONUS = 30_0000D;
    public static final Double THIRD_PRIZE_BONUS = 3000D;
    public static final Double FOURTH_PRIZE_BONUS = 200D;
    public static final Double FIFTH_PRIZE_BONUS = 10D;
    public static final Double SIXTH_PRIZE_BONUS = 5D;
    public static final Double NOT_WINNING_PRIZE_BONUS = 0D;

    public static final Double FIRST_PRIZE_WINNING_RATE = 0.000000056D;
    public static final Double SECOND_PRIZE_WINNING_RATE = 0.000000846D;
    public static final Double THIRD_PRIZE_WINNING_RATE = 0.00000914D;
    public static final Double FOURTH_PRIZE_WINNING_RATE = 0.000434D;
    public static final Double FIFTH_PRIZE_WINNING_RATE = 0.007758D;
    public static final Double SIXTH_PRIZE_WINNING_RATE = 0.05889D;

    public static final Double DEFAULT_UNIT_PRICE = 2D;

    private LotteryUtil() {}

    public static Double getExpectedValue(Double unitPrice, int buyNum) {
        Objects.requireNonNull(unitPrice);
        if (buyNum <= 0) {
            throw new IllegalArgumentException("购买彩票数量只能为大于0的正整数");
        }
        Double notWinningPrizeWinningRate = 1 - buyNum * (
                FIRST_PRIZE_WINNING_RATE + SECOND_PRIZE_WINNING_RATE + THIRD_PRIZE_WINNING_RATE
                + FOURTH_PRIZE_WINNING_RATE + FIFTH_PRIZE_WINNING_RATE + SIXTH_PRIZE_WINNING_RATE
                );
        return (FIRST_PRIZE_BONUS - unitPrice * buyNum) * FIRST_PRIZE_WINNING_RATE
                + (SECOND_PRIZE_BONUS - unitPrice * buyNum) * SECOND_PRIZE_WINNING_RATE
                + (THIRD_PRIZE_BONUS - unitPrice * buyNum) * THIRD_PRIZE_WINNING_RATE
                + (FOURTH_PRIZE_BONUS - unitPrice * buyNum) * FOURTH_PRIZE_WINNING_RATE
                + (FIFTH_PRIZE_BONUS - unitPrice * buyNum) * FIFTH_PRIZE_WINNING_RATE
                + (SIXTH_PRIZE_BONUS - unitPrice * buyNum) * SIXTH_PRIZE_WINNING_RATE
                + (NOT_WINNING_PRIZE_BONUS - unitPrice * buyNum) * notWinningPrizeWinningRate;
    }

    public static Double getExpectedValue(int buyNum) {
        return getExpectedValue(DEFAULT_UNIT_PRICE, buyNum);
    }

    public static Double getVariance(int buyNum) {
        return getVariance(DEFAULT_UNIT_PRICE, buyNum);
    }

    public static Double getVariance(Double unitPrice, int buyNum) {
        Objects.requireNonNull(unitPrice);
        Double expectedValue = getExpectedValue(unitPrice, buyNum);
        final int SQRT_NUMBER = 2;
        Double notWinningPrizeWinningRate = 1 - buyNum * (
                FIRST_PRIZE_WINNING_RATE + SECOND_PRIZE_WINNING_RATE + THIRD_PRIZE_WINNING_RATE
                        + FOURTH_PRIZE_WINNING_RATE + FIFTH_PRIZE_WINNING_RATE + SIXTH_PRIZE_WINNING_RATE
        );
        Double varianceVal = Math.pow(FIRST_PRIZE_BONUS - expectedValue, SQRT_NUMBER) * FIRST_PRIZE_WINNING_RATE +
                Math.pow(SECOND_PRIZE_BONUS - expectedValue, SQRT_NUMBER) * SECOND_PRIZE_WINNING_RATE +
                Math.pow(THIRD_PRIZE_BONUS - expectedValue, SQRT_NUMBER) * THIRD_PRIZE_WINNING_RATE +
                Math.pow(FOURTH_PRIZE_BONUS - expectedValue, SQRT_NUMBER) * FOURTH_PRIZE_WINNING_RATE +
                Math.pow(FIFTH_PRIZE_BONUS - expectedValue, SQRT_NUMBER) * FIFTH_PRIZE_WINNING_RATE +
                Math.pow(SIXTH_PRIZE_BONUS - expectedValue, SQRT_NUMBER) * SIXTH_PRIZE_WINNING_RATE +
                Math.pow(NOT_WINNING_PRIZE_BONUS - expectedValue, SQRT_NUMBER) * notWinningPrizeWinningRate;
        return varianceVal;
    }

    public static Double getStandardDeviation(int buyNum) {
        return getStandardDeviation(DEFAULT_UNIT_PRICE, buyNum);
    }

    public static Double getStandardDeviation(Double unitPrice, int buyNum) {
        Objects.requireNonNull(unitPrice);
        Double varianceVal = getVariance(unitPrice, buyNum);
        return Math.sqrt(varianceVal);
    }

    public static void main(String[] args) {
        int buyNum = 1;

        System.out.println(showWinningRote(buyNum));
        // System.out.println(LotteryUtil.getExpectedValue(buyNum));
        System.out.println(LotteryUtil.getVariance(buyNum));
        System.out.println(LotteryUtil.getStandardDeviation(buyNum));
    }

    public static Map<String, Double> showWinningRote(int buyNum) {
        Double notWinningPrizeWinningRate = 1 - buyNum * (
                FIRST_PRIZE_WINNING_RATE + SECOND_PRIZE_WINNING_RATE + THIRD_PRIZE_WINNING_RATE
                        + FOURTH_PRIZE_WINNING_RATE + FIFTH_PRIZE_WINNING_RATE + SIXTH_PRIZE_WINNING_RATE
        );
        Map<String, Double> result = new HashMap<>();
        result.put("1等奖机率", FIRST_PRIZE_WINNING_RATE * buyNum);
        result.put("2等奖机率", SECOND_PRIZE_WINNING_RATE * buyNum);
        result.put("3等奖机率", THIRD_PRIZE_WINNING_RATE * buyNum);
        result.put("4等奖机率", FOURTH_PRIZE_WINNING_RATE * buyNum);
        result.put("5等奖机率", FIFTH_PRIZE_WINNING_RATE * buyNum);
        result.put("6等奖机率", SIXTH_PRIZE_WINNING_RATE * buyNum);
        result.put("不中奖机率", notWinningPrizeWinningRate);
        System.out.println(">>>" + buyNum * (
                FIRST_PRIZE_WINNING_RATE + SECOND_PRIZE_WINNING_RATE + THIRD_PRIZE_WINNING_RATE
                        + FOURTH_PRIZE_WINNING_RATE + FIFTH_PRIZE_WINNING_RATE + SIXTH_PRIZE_WINNING_RATE
        ));
        return result;
    }

}